!>
!! @mainpage NCAR's WRF-Hydro NUOPC Cap
!! @author Daniel Rosen (daniel.rosen@noaa.gov)
!! @author ESMF Support (esmf_support@ucar.edu)
!! @date 03/14/2017 WRF-Hydro NUOPC Cap Added to GitHub
!! @date 03/17/2017 Documentation Added
!!
!! @tableofcontents
!!
!! @section Overview Overview
!!
!! The Weather Research and Forecasting Hydrological (WRF-Hydro) model is a
!! hydrometerological forecasting model developed and maintained by the
!! National Center for Atmospheric Research (NCAR). The WRF-Hydro cap wraps
!! the WRF-Hydro model with NUOPC compliant interfaces. The result is a
!! WRF-Hydro model capable of coupling with other models using National
!! Unified Operational Prediction Capability (NUOPC).
!!
!! This page documents the technical design of the specialized NUOPC model and
!! the WRF-Hydro gluecode. For generic NUOPC model documentation please see
!! the NUOPC reference manual: https://www.earthsystemcog.org/projects/nuopc/refmans.
!!
!!
!! @section NuopcSpecialization NUOPC Model Specialized Entry Points
!!
!! This cap specializes the cap configuration, initialization, advertised
!! fields, realized fields, data initialization, clock, run, and finalize.
!!
!! @subsection SetServices Set Services (Register Subroutines)
!!
!! Table summarizing the NUOPC specialized subroutines registered during
!! [SetServices] (@ref WRFHYDRO_NUOPC::SetServices).  The "Phase" column says
!! whether the subroutine is called during the initialization, run, or
!! finalize part of the coupled system run.
!!
!! Phase  |     Cap Subroutine                                | Description
!! -------|---------------------------------------------------|-------------------------------------------------------------
!! Init   | [InitializeP0] (@ref WRFHYDRO_NUOPC::InitializeP0)     | Set the Initialize Phase Definition (IPD). Configure model
!! Init   | [InitializeP1] (@ref WRFHYDRO_NUOPC::InitializeP1)     | Initialize model.  Advertize import and export fields
!! Init   | [InitializeP3] (@ref WRFHYDRO_NUOPC::InitializeP3)     | Realize import and export fields
!! Init   | [DataInitialize] (@ref WRFHYDRO_NUOPC::DataInitialize) | Initialize import and export data
!! Init   | [SetClock] (@ref WRFHYDRO_NUOPC::SetClock)             | Set model clock during initialization
!! Run    | [CheckImport] (@ref WRFHYDRO_NUOPC::CheckImport)       | Check timestamp on import data.
!! Run    | [ModelAdvance] (@ref WRFHYDRO_NUOPC::ModelAdvance)     | Advances the model by a timestep
!! Final  | [ModelFinalize] (@ref WRFHYDRO_NUOPC::ModelFinalize)   | Releases memory
!!
!!
!! @section Initialize Initialize
!!
!! Description of the initialization phases and internal model calls.
!! - [InitializeP0] (@ref WRFHYDRO_NUOPC::InitializeP0)
!! - [InitializeP1] (@ref WRFHYDRO_NUOPC::InitializeP1)
!! - [InitializeP3] (@ref WRFHYDRO_NUOPC::InitializeP3)
!! - [DataInitialize] (@ref WRFHYDRO_NUOPC::DataInitialize)
!! - [SetClock] (@ref WRFHYDRO_NUOPC::SetClock)
!!
!! @subsection InitializeP0 InitializeP0
!!
!! During initialize phase 0 the runtime configuration is read in from model
!! attributes and the initialization phase definition version is set to
!! IPDv03.
!!
!! @subsection InitializeP1 InitializeP1
!!
!! During initialize phase 1 the model is initialized and the import and
!! export fields are advertised in a state labeled with the domain ID.
!!
!! @subsection InitializeP3 InitializeP3
!!
!! During initialize phase 3 import and export fields are realized if they are
!! connected through NUOPC. Realized fields are created on the WRF-Hydro grid.
!!
!! @subsection DataInitialize DataInitialize
!!
!! During data initialize this cap checks the timestamp of all import fields
!! dependent on a coupled model.  Once all dependent import fields have been
!! initialized this cap is marked initalized.
!!
!! @subsection SetClock SetClock
!!
!! During set clock the cap creates a new clock using the timestep configured
!! in te WRF-Hydro configuration file. The restart write time step is also
!! created and the restart write time accumulation tracker is reset to zero.
!!
!!
!! @section Run Run
!!
!! Description of the run phase(s) and internal model calls.
!! - [CheckImport] (@ref WRFHYDRO_NUOPC::CheckImport)
!! - [ModelAdvance] (@ref WRFHYDRO_NUOPC::ModelAdvance)
!!
!! @subsection CheckImport CheckImport
!!
!! During check import the import data is checked to verify that it is at
!! the beginning or end of the timestep.
!!
!! @subsection ModelAdvance ModelAdvance
!!
!! Calls WRF-Hydro advance for the configured domain.
!!
!!
!! @section Finalize Finalize
!!
!! Description of the finalize phase and internal model calls.
!! - [ModelFinalize] (@ref WRFHYDRO_NUOPC::ModelFinalize)
!!
!! @subsection ModelFinalize ModelFinalize
!!
!! During model finalize WRF-Hydro finalize subroutines are called and memory
!! allocated during cap initialization is released.
!!
!!
!! @section ModelConfiguration Model Configuration
!!
!! Custom model attributes are used to configure the model.
!!
!! Attribute          | Default         | Description
!! -------------------|------------------|-----------------------------------------------------------------------------------
!! Verbosity          | 0                | String, converted into an integer. Bit 16: LIS cap information will be logged.
!! Diagnostic         | 0                | String, converted into an integer. Bit 16: LIS cap diagnostics will be written.
!! realize_all_export | false            | Realize all export fields including non connected fields.
!! config_file        | hydro.namelist   | Override the WRF-Hydro configuration file.
!! das_config_file    | namelist.hrldas  | Override the WRF-Hydro DAS configuration file.
!! time_step          | 0                | Override the WRF-Hydro time step. Value 0: Does not override time step.
!! forcings_directory | WRFHYDRO_FORCING | Override the WRF-Hydro forcings directory.
!! domain_id          | 1                | Set the WRF-Hydro domain identifier.
!! nest_to_nest       | false            | Turn on nest to nest coupling. Each nest will be identified with an integer.
!! import_dependency  | false            | Data initialization will loop until all import field dependencies are satisfied.
!! output_directory   | [CNAME]_OUTPUT   | Configure the WRF-Hydro Cap output directory.
!! multi_instance_hyd | false            | Run multiple instances of WRF-Hydro, each in a different directory.
!!
!!
!! @section ModelFields Model Fields
!!
!! The following tables list the import and export fields.
!!
!! @subsection ImportFields Import Fields
!!
!! Import fields are listed in the import_list parameter.
!!
!! Standard Name  | Units  | Model Variable  | Description                                | Notes
!! ---------------|--------|-----------------|--------------------------------------------|--------------------------------------
!! dummy_field_1  | Pa     | forcing_1       | field description for first import field   | |
!! dummy_field_2  | kg     | forcing_2       | field description for second import field  | |
!! dummy_field_3  | W m-2  | forcing_3       | field description for third import field   | field notes
!!
!! @subsection ExportField Export Fields
!!
!! Export fields are listed in the export_list parameter.
!!
!! Standard Name  | Units   | Model Variable  | Description                               | Notes
!! ---------------|---------|-----------------|-------------------------------------------|---------------------------
!! dummy_field_1  | m       | output_1        | field description for first export field  | field notes
!! dummy_field_2  | kg      | output_2        | field description for second export field | |
!! dummy_field_3  | m s-1   | output_3        | field description for third export field  | field notes
!!
!!
!! @section MemoryManagement Memory Management
!!
!! Model configuration is stored in a custom internal state data type. A
!! pointer to the custom internal state data type is stored in the component.
!!
!! The cap allocates new memory for each field.  This will be updated so that
!! NUOPC fields directly access the WRF-Hydro field memory.
!!
!! @section IO Input and Output
!!
!! Cap diagnostic output is written to the ESMF PET Logs. Cap diagnostic
!! output can be increased or decreased by setting the Verbosity attribute.
!!
!! NUOPC state restart write files are written depending on the
!! RestartInterval attribute. If set to 0 then NUOPC state restart write files
!! will never be written.
!!
!! WRF-Hydro diagnostics output is written to standard out. To increase the
!! diagnostic output compile WRF-Hydro with -DHYDRO_D.
!!
!! WRF-Hydro writes several output files.  Please see the
!! [WRF-Hydro documentation] (https://www.ral.ucar.edu/projects/wrf_hydro).
!!
!! @section Dependencies Dependencies
!!
!! Dependencies
!! - [ESMF v7.0.0+] (https://www.earthsystemcog.org/projects/esmf/)
!! - [NetCDF v4.3.0+] (http://www.unidata.ucar.edu/software/netcdf/docs/)
!! - [NetCDF FORTRAN] (http://www.unidata.ucar.edu/software/netcdf/docs/building_netcdf_fortran.html)
!!
!! @subsection ESMF ESMF
!!
!! See the [ESMF User's Guide]
!! (http://www.earthsystemmodeling.org/esmf_releases/public/last/ESMF_usrdoc).
!!
!! @section BuildingAndInstalling Building and Installing
!!
!! Environment Variables
!! - ESMFMKFILE
!!
!! NUOPC Makefile Targets
!! - nuopc
!! - nuopcinstall
!! - nuopcclean
!!
!! The build system in [Makefile] (@ref Makefile) wraps the WRF-Hydro build
!! system and adds the nuopc, nuopcinstall, and nuopcclean targets. Before
!! building make sure to configure the internal model.
!!
!! To build and install into the current directory run:
!!    $ make nuopc
!!
!! To install into an alternative directory run:
!!    $ make nuopcinstall DESTDIR=<INSTALL_DIR> INSTDIR=<SUBDIR>
!!
!! To build with debugging information run:
!!    $ make nuopc DEBUG=on
!!
!! @section Repository
!! The WRF-Hydro NUOPC cap is maintained in a GitHub repository:
!! https://github.com/NESII/wrfhydro_cap
!!
!! @section References
!!
!! - [WRF-Hydro] (https://www.ral.ucar.edu/projects/wrf_hydro)
!! - [ESPS] (https://www.earthsystemcog.org/projects/esps)
!! - [ESMF] (https://www.earthsystemcog.org/projects/esmf)
!! - [NUOPC] (https://www.earthsystemcog.org/projects/nuopc/)

#define FILENAME "WRFHydro_NUOPC_Cap.F90"
#define MODNAME "WRFHydro_NUOPC"
#include "WRFHydro_NUOPC_Macros.h"

module WRFHydro_NUOPC
  use ESMF
  use NUOPC
  use NUOPC_Model, &
    model_routine_SS        => SetServices, &
    model_label_DataInitialize => label_DataInitialize, &
    model_label_SetClock    => label_SetClock, &
    model_label_CheckImport => label_CheckImport, &
    model_label_Advance     => label_Advance, &
    model_label_Finalize    => label_Finalize
  use WRFHYDRO_NUOPC_Gluecode
  use WRFHYDRO_NUOPC_Fields
  use WRFHYDRO_NUOPC_Flags
  use WRFHydro_ESMF_Extensions

  implicit none

  private

  public SetServices

  CHARACTER(LEN=*), PARAMETER :: label_InternalState = 'InternalState'

  type type_InternalStateStruct
    logical                  :: realizeAllImport = .FALSE.
    logical                  :: realizeAllExport = .FALSE.
    character(len=64)        :: configFile       = 'hydro.namelist'
    character(len=64)        :: dasConfigFile    = 'namelist.hrldas'
    integer                  :: timeStepInt      = 0
    character(len=128)       :: forcingDir       = 'WRFHYDRO_FORCING'
    integer                  :: did              = 1
    logical                  :: nestToNest       = .FALSE.
    type(memory_flag)        :: memr_import      = MEMORY_POINTER
    type(memory_flag)        :: memr_export      = MEMORY_POINTER
    type(fillv_flag)         :: init_import      = FILLV_MODEL
    type(fillv_flag)         :: init_export      = FILLV_MODEL
    type(checkclock_flag)    :: chck_import      = CHECKCLOCK_CURRT
    type(missingval_flag)    :: misg_import      = MISSINGVAL_FAIL
    logical                  :: reset_import     = .FALSE.
    character(len=128)       :: dirOutput        = "./HYD_OUTPUT"
    character(len=128)       :: dirInput         = "./HYD_INPUT"
    logical                  :: writeRestart     = .FALSE.
    logical                  :: multiInstance    = .FALSE.
    character                :: hgrid            = '0'
    integer                  :: nnests           = 1
    type (ESMF_Clock)        :: clock(1)
    type (ESMF_TimeInterval) :: stepTimer(1)
    type(ESMF_State)         :: NStateImp(1)
    type(ESMF_State)         :: NStateExp(1)
    logical                  :: lsm_forcings(1)  = .FALSE.
  endtype

  type type_InternalState
    type(type_InternalStateStruct), pointer :: wrap
  end type

  !-----------------------------------------------------------------------------
  contains
  !-----------------------------------------------------------------------------

  subroutine SetServices(gcomp, rc)
    type(ESMF_GridComp)  :: gcomp
    integer, intent(out) :: rc

    ! local variables
    integer                    :: stat
    type(type_InternalState)   :: is

    rc = ESMF_SUCCESS

    ! allocate memory for this internal state and set it in the component
    allocate(is%wrap, stat=stat)
    if (ESMF_LogFoundAllocError(statusToCheck=stat, &
      msg='WRFHYDRO: Allocation of internal state memory failed.', &
      file=FILENAME, rcToReturn=rc)) return ! bail out
    call ESMF_UserCompSetInternalState(gcomp, label_InternalState, is, rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! the NUOPC model component will register the generic methods
    call NUOPC_CompDerive(gcomp, model_routine_SS, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! switching to IPD versions
    call ESMF_GridCompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, &
      userRoutine=InitializeP0, phase=0, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! set entry point for methods that require specific implementation
    call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, &
      phaseLabelList=(/"IPDv03p1"/), userRoutine=InitializeP1, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    call NUOPC_CompSetEntryPoint(gcomp, ESMF_METHOD_INITIALIZE, &
      phaseLabelList=(/"IPDv03p3"/), userRoutine=InitializeP3, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! attach specializing method(s)
    call NUOPC_CompSpecialize(gcomp, specLabel=model_label_DataInitialize, &
       specRoutine=DataInitialize, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call NUOPC_CompSpecialize(gcomp, speclabel=model_label_SetClock, &
      specRoutine=SetClock, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_MethodRemove(gcomp, label=model_label_CheckImport, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail ou
    call NUOPC_CompSpecialize(gcomp, specLabel=model_label_CheckImport, &
       specRoutine=CheckImport, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail ou
    call NUOPC_CompSpecialize(gcomp, speclabel=model_label_Advance, &
      specRoutine=ModelAdvance, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call NUOPC_CompSpecialize(gcomp, specLabel=model_label_Finalize, &
      specRoutine=ModelFinalize, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

  end subroutine

  !-----------------------------------------------------------------------------

  subroutine InitializeP0(gcomp, importState, exportState, clock, rc)
    type(ESMF_GridComp)   :: gcomp
    type(ESMF_State)      :: importState, exportState
    type(ESMF_Clock)      :: clock
    integer, intent(out)  :: rc

    ! local variables
    character(32)              :: cname
    character(*), parameter    :: rname="InitializeP0"
    integer                    :: verbosity, diagnostic
    character(len=64)          :: value
    type(type_InternalState)   :: is
    integer                    :: stat

    rc = ESMF_SUCCESS

    ! Query component for name, verbosity, and diagnostic values
!    call NUOPC_CompGet(gcomp, name=name, verbosity=verbosity, &
!      diagnostic=diagnostic, rc=rc)
    call ESMF_GridCompGet(gcomp, name=cname, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Diagnostic", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    diagnostic = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Verbosity", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    verbosity = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query Component for its internal State
    nullify(is%wrap)
    call ESMF_UserCompGetInternalState(gcomp, label_InternalState, is, rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! Switch to IPDv03 by filtering all other phaseMap entries
    call NUOPC_CompFilterPhaseMap(gcomp, ESMF_METHOD_INITIALIZE, &
      acceptStringList=(/"IPDv03p"/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    call WRFHydro_AttributeGet(rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! change directory for multiple instances
    if (is%wrap%multiInstance) then
      if (btest(verbosity,16)) then
        call ESMF_LogWrite(trim(cname)//": Change working directory", &
          ESMF_LOGMSG_INFO)
      endif
      call WRFHYDRO_ESMF_ChDir(trim(cname),rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    endif

    ! prepare diagnostics folder
    if (btest(diagnostic,16) .OR. is%wrap%writeRestart) then
      call ESMF_UtilIOMkDir(pathName=trim(is%wrap%dirOutput), &
        relaxedFlag=.true., rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    endif

    contains ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    subroutine WRFHydro_AttributeGet(rc)
      integer, intent(out)  :: rc

      ! local variables
      logical                    :: configIsPresent
      type(ESMF_Config)          :: config
      type(NUOPC_FreeFormat)     :: attrFF
      character(32)              :: atName
      logical                    :: atPres
      character(32)              :: atVal
      character(ESMF_MAXSTR)     :: logMsg

      ! check gcomp for config
      call ESMF_GridCompGet(gcomp, configIsPresent=configIsPresent, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out

      if (configIsPresent) then
        ! read and ingest free format component attributes
        call ESMF_GridCompGet(gcomp, config=config, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        attrFF = NUOPC_FreeFormatCreate(config, &
          label=trim(cname)//"_attributes::", relaxedflag=.true., rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        call NUOPC_CompAttributeIngest(gcomp, attrFF, addFlag=.true., rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        call NUOPC_FreeFormatDestroy(attrFF, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      endif

      ! Realize all import fields
      atName="realize_all_import"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        atVal = ESMF_UtilStringUpperCase(atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%realizeAllImport = (trim(atVal)=="TRUE")
      endif

      ! Realize all export fields
      atName="realize_all_export"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        atVal = ESMF_UtilStringUpperCase(atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%realizeAllExport = (trim(atVal)=="TRUE")
      endif

      ! Determine hydro configuration filename
      atName="config_file"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%configFile = atVal
      endif

      ! Determine DAS configuration filename
      atName="das_config_file"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%dasConfigFile = atVal
      endif

      ! Time Step
      atName="time_step"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        read (atVal,*,iostat=stat) is%wrap%timeStepInt
        if (stat /= 0) then
          call ESMF_LogSetError(ESMF_FAILURE, &
            msg="Cannot convert "//trim(atVal)//" to integer.", &
            line=__LINE__,file=__FILE__,rcToReturn=rc)
          return  ! bail out
        endif
      endif

      ! Forcing Directory
      atName="forcings_directory"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%forcingDir = trim(atVal)
      endif

      ! Determine Domain ID
      atName="did"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%did = ESMF_UtilString2Int(atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      endif

      ! Connect Nest to Nest
      atName="nest_to_nest"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        atVal = ESMF_UtilStringUpperCase(atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%nestToNest = (trim(atVal)=="TRUE")
      endif

      ! import data memory type
      atName="field_memory_import"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%memr_import = atVal
      endif

      ! export data memory type
      atName="field_memory_export"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%memr_export = atVal
      endif

      ! import data initialization type
      atName="initialize_import"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%init_import = atVal
      endif

      ! backwards compatible setting (overrides initialize_import)
      atName="import_dependency"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        atVal = ESMF_UtilStringUpperCase(atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        if (trim(atVal)=="TRUE") is%wrap%init_import = FILLV_DEPENDENCY
      endif

      ! export data initialization type
      atName="initialize_export"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%init_export = atVal
      endif

      ! backwards compatible setting (overrides initialize_export)
      atName="read_restart"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        atVal = ESMF_UtilStringUpperCase(atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        if (trim(atVal)=="TRUE") is%wrap%init_export = FILLV_FILE
      endif

      ! Get check import
      atName="check_import"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%chck_import = atVal
      endif

      ! Get missing import handler
      atName="missing_import"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%misg_import = atVal
      endif

      ! Get reset import handler
      atName="reset_import"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        atVal = ESMF_UtilStringUpperCase(atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%reset_import = (trim(atVal)=="TRUE")
      endif

      ! Get component output directory
      atName="output_directory"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%dirOutput = trim(atVal)
      endif

      ! Get component input directory
      atName="input_directory"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%dirInput = trim(atVal)
      endif

      ! Write cap restart state
      atName="write_restart"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        atVal = ESMF_UtilStringUpperCase(atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%writeRestart = (trim(atVal)=="TRUE")
      endif

      ! Determine Import Dependency
      atName="multi_instance_hyd"
      call NUOPC_CompAttributeGet(gcomp, name=atName, isPresent=atPres, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (atPres) then
        call NUOPC_CompAttributeGet(gcomp, name=atName, value=atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        atVal = ESMF_UtilStringUpperCase(atVal, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        is%wrap%multiInstance = (trim(atVal)=="TRUE")
      endif

      if (btest(verbosity,16)) then
        call ESMF_LogWrite(trim(cname)//": Settings",ESMF_LOGMSG_INFO)
        write (logMsg, "(A,(A,I0))") trim(cname)//": ", &
          "Verbosity              = ",verbosity
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        write (logMsg, "(A,(A,I0))") trim(cname)//": ", &
          "Diagnostic             = ",diagnostic
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        write (logMsg, "(A,(A,L1))") trim(cname)//": ", &
          "Realze All Imports     = ",is%wrap%realizeAllImport
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        write (logMsg, "(A,(A,L1))") trim(cname)//": ", &
          "Realze All Exports     = ",is%wrap%realizeAllExport
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        write (logMsg, "(A,(A,A))") trim(cname)//": ", &
          "Config File            = ",trim(is%wrap%configFile)
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        write (logMsg, "(A,(A,A))") trim(cname)//": ", &
          "DAS Config File        = ",trim(is%wrap%dasConfigFile)
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        write (logMsg, "(A,(A,I0))") trim(cname)//": ", &
          "Time Step Config       = ",is%wrap%timeStepInt
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        write (logMsg, "(A,(A,A))") trim(cname)//": ", &
          "Forcing Directory      = ",trim(is%wrap%forcingDir)
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        write (logMsg, "(A,(A,I0))") trim(cname)//": ", &
          "Domain ID              = ",is%wrap%did
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        write (logMsg, "(A,(A,L1))") trim(cname)//": ", &
          "Nest To Nest           = ",is%wrap%nestToNest
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        atVal = is%wrap%memr_import
        write (logMsg, "(A,(A,A))") trim(cname)//": ", &
          "Field Memory Import    = ",trim(atVal)
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        atVal = is%wrap%memr_export
        write (logMsg, "(A,(A,A))") trim(cname)//": ", &
          "Field Memory Export    = ",trim(atVal)
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        atVal = is%wrap%init_import
        write (logMsg, "(A,(A,A))") trim(cname)//": ", &
          "Initialize Import      = ",trim(atVal)
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        atVal = is%wrap%init_export
        write (logMsg, "(A,(A,A))") trim(cname)//": ", &
          "Initialize Export      = ",trim(atVal)
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        atVal = is%wrap%chck_import
        write (logMsg, "(A,(A,A))") trim(cname)//": ", &
          "Check Imports          = ",trim(atVal)
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        atVal = is%wrap%misg_import
        write (logMsg, "(A,(A,A))") trim(cname)//": ", &
          "Missing Imports        = ",trim(atVal)
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        write (logMsg, "(A,(A,L1))") trim(cname)//': ', &
          "Reset Import           = ",is%wrap%reset_import
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        write (logMsg, "(A,(A,A))") trim(cname)//": ", &
          "Output Directory       = ",trim(is%wrap%dirOutput)
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        write (logMsg, "(A,(A,A))") trim(cname)//": ", &
          "Input Directory        = ",trim(is%wrap%dirInput)
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        write (logMsg, "(A,(A,L1))") trim(cname)//': ', &
          "Write Restart          = ",is%wrap%writeRestart
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
        write (logMsg, "(A,(A,L1))") trim(cname)//': ', &
          "Multiple Instances     = ",is%wrap%multiInstance
        call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
      endif

    end subroutine

  end subroutine

  !-----------------------------------------------------------------------------

  subroutine InitializeP1(gcomp, importState, exportState, clock, rc)
    type(ESMF_GridComp)  :: gcomp
    type(ESMF_State)     :: importState, exportState
    type(ESMF_Clock)     :: clock
    integer, intent(out) :: rc

    ! local variables
    character(32)               :: cname
    character(*), parameter     :: rname="InitializeP1"
    integer                     :: verbosity, diagnostic
    character(len=64)           :: value
    type(type_InternalState)    :: is
    type(ESMF_VM)               :: vm
    integer                     :: fIndex
    character(len=9)            :: nStr

    rc = ESMF_SUCCESS

    ! Query component for name, verbosity, and diagnostic values
!    call NUOPC_CompGet(gcomp, name=name, verbosity=verbosity, &
!      diagnostic=diagnostic, rc=rc)
    call ESMF_GridCompGet(gcomp, name=cname, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Diagnostic", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    diagnostic = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Verbosity", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    verbosity = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query Component for its internal State
    nullify(is%wrap)
    call ESMF_UserCompGetInternalState(gcomp, label_InternalState, is, rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! initialize wrfhydro
    call ESMF_GridCompGet(gcomp, vm=vm, rc=rc)
    if(ESMF_STDERRORCHECK(rc)) return ! bail out

    call wrfhydro_nuopc_ini(is%wrap%did,vm,clock,is%wrap%forcingDir,rc=rc)
    if(ESMF_STDERRORCHECK(rc)) return ! bail out

    ! get hgrid for domain id
    call WRFHYDRO_get_hgrid(is%wrap%did,is%wrap%hgrid,rc=rc)
    if(ESMF_STDERRORCHECK(rc)) return ! bail out

    ! add namespace
    if(.NOT.is%wrap%nestToNest) then
      is%wrap%NStateImp(1) = importState
      is%wrap%NStateExp(1) = exportState
    else
      write (nStr,"(I0)") is%wrap%did
      call NUOPC_AddNestedState(importState, &
        CplSet=trim(is%wrap%hgrid), &
        nestedStateName="NestedStateImp_N"//trim(nStr), &
        nestedState=is%wrap%NStateImp(1), rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      call NUOPC_AddNestedState(exportState, &
        CplSet=trim(is%wrap%hgrid), &
        nestedStateName="NestedStateExp_N"//trim(nStr), &
        nestedState=is%wrap%NStateExp(1), rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    endif

    call field_dictionary_add(fieldList=cap_fld_list, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    !!
    !! advertise import and export fields
    !!
    call field_advertise(fieldList=cap_fld_list, &
      importState=is%wrap%NStateImp(1), &
      exportState=is%wrap%NStateExp(1), &
      rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    if (btest(verbosity,16)) call field_advertise_log(cap_fld_list,cname,rc=rc)

  end subroutine

  !-----------------------------------------------------------------------------

  subroutine InitializeP3(gcomp, importState, exportState, clock, rc)
    type(ESMF_GridComp)         :: gcomp
    type(ESMF_State)            :: importState, exportState
    type(ESMF_Clock)            :: clock
    integer, intent(out)        :: rc

    ! local variables
    character(32)              :: cname
    character(*), parameter    :: rname="InitializeP3"
    integer                    :: verbosity, diagnostic
    character(len=64)          :: value
    type(type_InternalState)   :: is
    type(ESMF_Grid)            :: WRFHYDRO_Grid
    type(ESMF_Field)           :: field
    logical                    :: importConnected, exportConnected
    integer                    :: fIndex
    character(len=9)           :: nStr

    rc = ESMF_SUCCESS

    ! Query component for name, verbosity, and diagnostic values
!    call NUOPC_CompGet(gcomp, name=name, verbosity=verbosity, &
!      diagnostic=diagnostic, rc=rc)
    call ESMF_GridCompGet(gcomp, name=cname, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Diagnostic", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    diagnostic = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Verbosity", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    verbosity = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query Component for its internal State
    nullify(is%wrap)
    call ESMF_UserCompGetInternalState(gcomp, label_InternalState, is, rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    write (nStr,"(I0)") is%wrap%did

    ! call gluecode to create grid
    WRFHYDRO_Grid = WRFHYDRO_GridCreate(is%wrap%did,rc=rc)
    if(ESMF_STDERRORCHECK(rc)) return ! bail out

    if (btest(verbosity,16)) then
      call WRFHYDRO_ESMF_LogGrid(WRFHYDRO_Grid, &
        trim(cname)//"_"//rname//"_D"//trim(nStr),rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    endif

    ! Write grid to NetCDF file.
    if (btest(diagnostic,16)) then
      call WRFHYDRO_ESMF_GridWrite(WRFHYDRO_Grid, &
        trim(is%wrap%dirOutput)//"/diag_"//trim(cname)//"_"// &
        rname//'_grid_D'//trim(nStr)//".nc", rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    endif

    call field_realize(fieldList=cap_fld_list, &
      importState=is%wrap%NStateImp(1), &
      exportState=is%wrap%NStateExp(1), &
      grid=WRFHYDRO_grid, did=is%wrap%did, &
      realizeAllImport=is%wrap%realizeAllImport, &
      realizeAllExport=is%wrap%realizeAllExport, &
      memr_import=is%wrap%memr_import, &
      memr_export=is%wrap%memr_export, &
      rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    is%wrap%lsm_forcings(1) = check_lsm_forcings(is%wrap%NStateImp(1),rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    if (btest(verbosity,16)) call field_realize_log(cap_fld_list,cname,rc=rc)
    if (btest(verbosity,16)) call LogMode()

    contains ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    !---------------------------------------------------------------------------

    subroutine LogMode()
      ! local variables
      character(ESMF_MAXSTR)     :: logMsg
      character(len=64)          :: modeStr

      if(is%wrap%lsm_forcings(1)) then
        modeStr = "WRFHYDRO_Coupled"
      else
        modeStr = "WRFHYDRO_Offline"
      endif
      write (logMsg, "(A,(A,A))") trim(cname)//": ", &
        "Mode = ",trim(modeStr)
      call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)

    end subroutine

  end subroutine

  !-----------------------------------------------------------------------------

  subroutine DataInitialize(gcomp, rc)
    type(ESMF_GridComp)  :: gcomp
    integer, intent(out) :: rc

    ! local variables
    character(32)                          :: cname
    character(*), parameter                :: rname="DataInitialize"
    integer                                :: verbosity, diagnostic
    character(len=64)                      :: value
    type(type_InternalState)               :: is
    type(ESMF_Clock)                       :: modelClock
    type(ESMF_Time)                        :: currTime
    type(ESMF_Time)                        :: invalidTime
    character(len=32)                      :: currTimeStr
    character(len=9)                       :: nStr
    logical                                :: importCurrent
    logical                                :: importUpdated
    logical                                :: exportUpdated
    character(len=32)                      :: initTypeStr
    logical                                :: mdlRestart
    integer                                :: stat

    rc = ESMF_SUCCESS

    ! Query component for name, verbosity, and diagnostic values
!    call NUOPC_CompGet(gcomp, name=name, verbosity=verbosity, &
!      diagnostic=diagnostic, rc=rc)
    call ESMF_GridCompGet(gcomp, name=cname, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Diagnostic", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    diagnostic = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Verbosity", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    verbosity = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query Component for its internal State
    nullify(is%wrap)
    call ESMF_UserCompGetInternalState(gcomp, label_InternalState, is, rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query the Component for its clock
    call NUOPC_ModelGet(gcomp, modelClock=modelClock, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! set up invalid time (by convention)
    call ESMF_TimeSet(invalidTime, yy=99999999, mm=01, dd=01, &
      h=00, m=00, s=00, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! get the current time out of the clock
    call ESMF_ClockGet(modelClock, currTime=currTime, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_TimeGet(currTime, timeString=currTimeStr, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    write (nStr,"(I0)") is%wrap%did

    ! initialize import state
    if (is%wrap%init_import.eq.FILLV_MISSING) then
      call state_fill_uniform(is%wrap%NStateImp(1), &
        fillValue=ESMF_MISSING_VALUE, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return
      call NUOPC_SetTimestamp(is%wrap%NStateImp(1), time=invalidTime, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      importUpdated = .TRUE.
    elseif (is%wrap%init_import.eq.FILLV_ZERO) then
      call state_fill_uniform(is%wrap%NStateImp(1), &
        fillValue=0.0_ESMF_KIND_R8, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return
      call NUOPC_SetTimestamp(is%wrap%NStateImp(1), time=invalidTime, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      importUpdated = .TRUE.
    elseif (is%wrap%init_import.eq.FILLV_DEPENDENCY) then
      importCurrent = NUOPC_IsAtTime(is%wrap%NStateImp(1), &
        time=currTime, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (importCurrent) then
        call ESMF_LogWrite( &
          trim(cname)//': '//rname//' Initialize-Data-Dependency SATISFIED!!! Nest='//trim(nStr), &
          ESMF_LOGMSG_INFO)
        importUpdated = .TRUE.
      else
        call ESMF_LogWrite( &
          trim(cname)//': '//rname//' Initialize-Data-Dependency NOT YET SATISFIED!!! Nest='//trim(nStr), &
          ESMF_LOGMSG_INFO)
        importUpdated = .FALSE.
      endif
    elseif (is%wrap%init_import.eq.FILLV_PRESCRIBE) then
      call state_fill_prescribe(is%wrap%NStateImp(1), &
        fieldList=cap_fld_list, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return
      importUpdated = .TRUE.
    elseif (is%wrap%init_import.eq.FILLV_FILE) then
      call state_fill_file(is%wrap%NStateImp(1), &
        filePrefix=trim(is%wrap%dirInput)//"/restart_"//trim(cname)// &
          "_imp_D"//trim(nStr)//"_"//trim(currTimeStr), rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return
      call NUOPC_SetTimestamp(is%wrap%NStateImp(1), time=currTime, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      importUpdated = .TRUE.
    elseif (is%wrap%init_import.eq.FILLV_MODEL) then
      if (is%wrap%memr_import.eq.MEMORY_COPY) then
        call state_copy_frhyd(is%wrap%NStateImp(1), is%wrap%did, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      endif
      call WRFHYDRO_get_restart(is%wrap%did, restart=mdlRestart, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (mdlRestart) then
        call NUOPC_SetTimestamp(is%wrap%NStateImp(1), time=currTime, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      else
        call NUOPC_SetTimestamp(is%wrap%NStateImp(1), time=invalidTime, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      endif
      importUpdated = .TRUE.
    else
      initTypeStr = is%wrap%init_import
      call ESMF_LogSetError(ESMF_FAILURE, &
        msg="Import data initialize routine unknown "//trim(initTypeStr), &
        line=__LINE__,file=__FILE__,rcToReturn=rc)
      return  ! bail out
      importUpdated = .FALSE.
    endif

    ! initialize export state
    if (is%wrap%init_export.eq.FILLV_MISSING) then
      call state_fill_uniform(is%wrap%NStateExp(1), &
        fillValue=ESMF_MISSING_VALUE, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return
      call NUOPC_SetTimestamp(is%wrap%NStateExp(1), time=invalidTime, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      exportUpdated = .TRUE.
    elseif (is%wrap%init_export.eq.FILLV_ZERO) then
      call state_fill_uniform(is%wrap%NStateExp(1), &
        fillValue=0.0_ESMF_KIND_R8, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return
      call NUOPC_SetTimestamp(is%wrap%NStateExp(1), time=invalidTime, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      exportUpdated = .TRUE.
    elseif (is%wrap%init_export.eq.FILLV_PRESCRIBE) then
      call state_fill_prescribe(is%wrap%NStateExp(1), &
        fieldList=cap_fld_list, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return
      exportUpdated = .TRUE.
    elseif (is%wrap%init_export.eq.FILLV_FILE) then
      call state_fill_file(is%wrap%NStateExp(1), &
        filePrefix=trim(is%wrap%dirInput)//"/restart_"//trim(cname)// &
          "_exp_D"//trim(nStr)//"_"//trim(currTimeStr), rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return
      call NUOPC_SetTimestamp(is%wrap%NStateExp(1), time=currTime, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      exportUpdated = .TRUE.
    elseif (is%wrap%init_export.eq.FILLV_MODEL) then
      if (is%wrap%memr_export.eq.MEMORY_COPY) then
        call state_copy_frhyd(is%wrap%NStateExp(1), is%wrap%did, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      endif
      call WRFHYDRO_get_restart(is%wrap%did, restart=mdlRestart, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      if (mdlRestart) then
        call NUOPC_SetTimestamp(is%wrap%NStateExp(1), time=currTime, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      else
        call NUOPC_SetTimestamp(is%wrap%NStateExp(1), time=invalidTime, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      endif
      exportUpdated = .TRUE.
    else
      initTypeStr = is%wrap%init_export
      call ESMF_LogSetError(ESMF_FAILURE, &
        msg="Export data initialize routine unknown "//trim(initTypeStr), &
        line=__LINE__,file=__FILE__,rcToReturn=rc)
      return  ! bail out
      exportUpdated = .FALSE.
    endif

    ! set InitializeDataComplete Attribute to "true", indicating to the
    ! generic code that all inter-model data dependencies are satisfied
    if (importUpdated.AND.exportUpdated) then
      call NUOPC_CompAttributeSet(gcomp, name="InitializeDataComplete", value="true", rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      ! Write initialization files
      if (btest(diagnostic,16)) then
        call NUOPC_Write(is%wrap%NStateImp(1), &
          fileNamePrefix=trim(is%wrap%dirOutput)//"/diag_"//trim(cname)//"_"// &
            rname//"_imp_D"//trim(nStr)//"_"//trim(currTimeStr)//"_", &
          overwrite=.true., status=ESMF_FILESTATUS_REPLACE, timeslice=1, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        call NUOPC_Write(is%wrap%NStateExp(1), &
          fileNamePrefix=trim(is%wrap%dirOutput)//"/diag_"//trim(cname)//"_"// &
            rname//"_exp_D"//trim(nStr)//"_"//trim(currTimeStr)//"_", &
          overwrite=.true., status=ESMF_FILESTATUS_REPLACE, timeslice=1, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      endif
    endif

  end subroutine

  !-----------------------------------------------------------------------------

  subroutine SetClock(gcomp, rc)
    type(ESMF_GridComp)  :: gcomp
    integer, intent(out) :: rc

    ! local variables
    character(32)              :: cname
    character(*), parameter    :: rname="SetClock"
    integer                    :: verbosity, diagnostic
    character(len=64)          :: value
    type(type_InternalState)   :: is
    integer                    :: dt
    type(ESMF_Clock)           :: modelClock
    type(ESMF_TimeInterval)    :: timeStep

    rc = ESMF_SUCCESS

    ! Query component for name, verbosity, and diagnostic values
!    call NUOPC_CompGet(gcomp, name=name, verbosity=verbosity, &
!      diagnostic=diagnostic, rc=rc)
    call ESMF_GridCompGet(gcomp, name=cname, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Diagnostic", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    diagnostic = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Verbosity", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    verbosity = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query Component for its internal State
    nullify(is%wrap)
    call ESMF_UserCompGetInternalState(gcomp, label_InternalState, is, rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query the Component for its clock
    call NUOPC_ModelGet(gcomp, modelClock=modelClock, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query the clock for its timestep
    call ESMF_ClockGet(modelClock, timeStep=timeStep, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query the timestep for seconds
    call ESMF_TimeIntervalGet(timestep,s=dt,rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! override timestep
    if (is%wrap%timeStepInt /= 0) then
      call ESMF_TimeIntervalSet(timestep, &
        s=is%wrap%timeStepInt, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      call WRFHYDRO_set_timestep(is%wrap%did,real(is%wrap%timeStepInt),rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      call ESMF_ClockSet(modelClock, timeStep=timeStep, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    else
      call WRFHYDRO_set_timestep(is%wrap%did,real(dt),rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    endif

    call NUOPC_CompSetClock(gcomp, modelClock, timeStep, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    is%wrap%clock(1) = modelClock

    ! Reset Timers
    call ESMF_TimeIntervalSet(is%wrap%stepTimer(1), &
      s_r8=0._ESMF_KIND_R8, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    if (btest(verbosity,16)) call LogClock()

    contains ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    subroutine LogClock()
      ! local variables
      character(ESMF_MAXSTR)     :: logMsg
      type(ESMF_Time)            :: currTime
      type(ESMF_TimeInterval)    :: timestep
      character(len=64)          :: currTimeStr
      character(len=64)          :: timestepStr

      if (ESMF_ClockIsCreated(is%wrap%clock(1))) then
        call ESMF_ClockGet(is%wrap%clock(1), &
          currTime=currTime,timeStep=timestep,rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        call ESMF_TimeGet(currTime, &
          timeString=currTimeStr,rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        call ESMF_TimeIntervalGet(timestep, &
          timeString=timestepStr,rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      else
        currTimeStr = "(not_created)"
        timestepStr = "(not_created)"
      endif

      write (logMsg, "(A,(A,A))") trim(cname)//": ", &
        "Current Time = ",trim(currTimeStr)
      call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
      write (logMsg, "(A,(A,A))") trim(cname)//": ", &
        "Time Step    = ",trim(timestepStr)
      call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)

    end subroutine

  end subroutine

  !-----------------------------------------------------------------------------

subroutine CheckImport(gcomp, rc)
    type(ESMF_GridComp) :: gcomp
    integer,intent(out) :: rc

    ! local variables
    character(32)               :: cname
    character(*), parameter     :: rname="CheckImport"
    integer                     :: verbosity, diagnostic
    character(len=64)           :: value
    type(type_InternalState)    :: is
    integer                     :: nIndex
    character(len=10)           :: sStr
    type(ESMF_Clock)            :: modelClock
    type(ESMF_Time)             :: modelCurrTime
    logical                     :: allCurrTime

    rc = ESMF_SUCCESS

    ! Query component for name, verbosity, and diagnostic values
!    call NUOPC_CompGet(gcomp, name=name, verbosity=verbosity, &
!      diagnostic=diagnostic, rc=rc)
    call ESMF_GridCompGet(gcomp, name=cname, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Diagnostic", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    diagnostic = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Verbosity", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    verbosity = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query Component for its internal State
    nullify(is%wrap)
    call ESMF_UserCompGetInternalState(gcomp, label_InternalState, is, rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query the Component for its clock
    call NUOPC_ModelGet(gcomp, modelClock=modelClock, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! get the curr time out of the clock
    call ESMF_ClockGet(modelClock, currTime=modelCurrTime, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! check that Fields in the importState show correct timestamp

    allCurrTime = NUOPC_IsAtTime(is%wrap%NStateImp(1), modelCurrTime, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    if (.not.allCurrTime) then
      call ESMF_LogWrite(trim(cname)//": NUOPC INCOMPATIBILITY DETECTED: "// &
        "Import Fields not at correct time", &
        ESMF_LOGMSG_WARNING)
    endif

  end subroutine

  !-----------------------------------------------------------------------------

  subroutine ModelAdvance(gcomp, rc)
    type(ESMF_GridComp)  :: gcomp
    integer, intent(out) :: rc

    ! local variables
    character(32)               :: cname
    character(*), parameter     :: rname="ModelAdvance"
    integer                     :: verbosity, diagnostic
    character(len=64)           :: value
    type(type_InternalState)    :: is
    character(len=10)           :: sStr
    type(ESMF_Clock)            :: modelClock
    type(ESMF_State)            :: importState, exportState
    type(ESMF_Time)             :: currTime, advEndTime
    character(len=32)           :: currTimeStr, advEndTimeStr
    type(ESMF_TimeInterval)     :: timeStep
    character(len=9)            :: nStr
    character(len=16)           :: misgValTypeStr

    rc = ESMF_SUCCESS

    ! Query component for name, verbosity, and diagnostic values
!    call NUOPC_CompGet(gcomp, name=name, verbosity=verbosity, &
!      diagnostic=diagnostic, rc=rc)
    call ESMF_GridCompGet(gcomp, name=cname, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Diagnostic", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    diagnostic = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Verbosity", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    verbosity = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query component for its internal State
    nullify(is%wrap)
    call ESMF_UserCompGetInternalState(gcomp, label_InternalState, is, rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query the component for its clock, importState, and exportState
    call NUOPC_ModelGet(gcomp, &
      modelClock=modelClock, &
      importState=importState, &
      exportState=exportState, &
      rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query the clock for its current time and timestep
    call ESMF_ClockGet(modelClock, &
      currTime=currTime, timeStep=timeStep, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    advEndTime = currTime + timeStep
    call ESMF_TimeGet(currTime, timeString=currTimeStr, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_TimeGet(advEndTime, timeString=advEndTimeStr, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    write (nStr,"(I0)") is%wrap%did

    ! Write import files
    if (btest(diagnostic,16)) then
      call NUOPC_Write(is%wrap%NStateImp(1), &
        fileNamePrefix=trim(is%wrap%dirOutput)//"/diag_"//trim(cname)//"_"// &
          rname//"_imp_D"//trim(nStr)//"_"//trim(currTimeStr)//"_", &
        overwrite=.true., status=ESMF_FILESTATUS_REPLACE, timeslice=1, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    endif

    if (is%wrap%memr_import.eq.MEMORY_COPY) then
      call state_copy_tohyd(is%wrap%NStateImp(1), is%wrap%did, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    endif

    if (is%wrap%misg_import.eq.MISSINGVAL_FAIL) then
      call state_check_missing(is%wrap%NStateImp(1), did=is%wrap%did, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    elseif (is%wrap%misg_import.eq.MISSINGVAL_PRESCRIBE) then
      call state_prescribe_missing(is%wrap%NStateImp(1), did=is%wrap%did, &
        fieldList=cap_fld_list, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    elseif (is%wrap%misg_import.eq.MISSINGVAL_IGNORE) then
!     DO NOTHING
    else
      misgValTypeStr = is%wrap%misg_import
      call ESMF_LogSetError(ESMF_FAILURE, &
        msg="Unknown missing value handler "//trim(misgValTypeStr), &
        line=__LINE__,file=__FILE__,rcToReturn=rc)
      return  ! bail out
    endif

    if (btest(diagnostic,16)) then
      call model_debug(is%wrap%NStateImp(1), did=is%wrap%did, &
        memflg=is%wrap%memr_import, &
        filePrefix=trim(is%wrap%dirOutput)//"/wrfhydro_"// &
          rname//"_imp_D"//trim(nStr)//"_"//trim(currTimeStr)//"_", rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    endif

    is%wrap%stepTimer(1) = is%wrap%stepTimer(1) + timeStep

    call ESMF_ClockGet(is%wrap%clock(1),timeStep=timestep,rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    do while (is%wrap%stepTimer(1) >= timestep)
      ! call wrfhydro advance
      if (btest(verbosity,16)) then
        call LogAdvance(nIndex=1,nStr=nStr)
      endif
      call wrfhydro_nuopc_run(is%wrap%did,is%wrap%lsm_forcings(1), &
        is%wrap%clock(1),is%wrap%NStateImp(1),is%wrap%NStateExp(1),rc)
      if(ESMF_STDERRORCHECK(rc)) return ! bail out
      call ESMF_ClockAdvance(is%wrap%clock(1),rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      is%wrap%stepTimer(1) = &
        is%wrap%stepTimer(1) - timestep
    enddo

    if (is%wrap%memr_export.eq.MEMORY_COPY) then
      call state_copy_frhyd(is%wrap%NStateExp(1), is%wrap%did, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    endif

    if (is%wrap%reset_import) then
      if ((is%wrap%memr_import.eq.MEMORY_POINTER) .AND. &
          (is%wrap%memr_export.eq.MEMORY_POINTER)) then
        call ESMF_LogSetError(ESMF_FAILURE, &
          msg="Cannot reset import field if pointer is shared with export.", &
          line=__LINE__,file=__FILE__,rcToReturn=rc)
        return  ! bail out
      else
        call state_fill_uniform(is%wrap%NStateImp(1), &
          fillValue=ESMF_MISSING_VALUE, rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return
      endif
    endif

    ! Write export files
    if (btest(diagnostic,16)) then
      call NUOPC_Write(is%wrap%NStateExp(1), &
        fileNamePrefix=trim(is%wrap%dirOutput)//"/diag_"//trim(cname)//"_"// &
          rname//"_exp_D"//trim(nStr)//"_"//trim(advEndTimeStr)//"_", &
        overwrite=.true., status=ESMF_FILESTATUS_REPLACE, timeslice=1, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    endif

    contains ! - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    subroutine LogAdvance(nIndex,nStr)
      integer                    :: nIndex
      character(len=9)           :: nStr
      ! local variables
      character(ESMF_MAXSTR)     :: logMsg
      character(len=32)          :: nModeStr
      type(ESMF_Time)            :: nestCurrTime
      type(ESMF_TimeInterval)    :: nestTimestep
      character(len=32)          :: nCurrTimeStr
      character(len=32)          :: nTimeStepStr

      call ESMF_LogWrite(trim(cname)//': '//rname//&
        ' Advancing Nest='//trim(nStr),ESMF_LOGMSG_INFO)

      if (is%wrap%lsm_forcings(nIndex)) then
        nModeStr = "WRFHYDRO_Coupled"
      else
        nModeStr = "WRFHYDRO_Offline"
      endif

      write (logMsg, "(A,(A,A,A),(A,A))") trim(cname)//': ', &
        'Nest(',trim(nStr),') ', &
        'Mode = ',trim(nModeStr)
      call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)

      if (ESMF_ClockIsCreated(is%wrap%clock(nIndex))) then
        call ESMF_ClockGet(is%wrap%clock(nIndex), &
          currTime=nestCurrTime,timeStep=nestTimestep,rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        call ESMF_TimeGet(nestCurrTime, &
          timeString=nCurrTimeStr,rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
        call ESMF_TimeIntervalGet(nestTimestep, &
          timeString=nTimeStepStr,rc=rc)
        if (ESMF_STDERRORCHECK(rc)) return  ! bail out
      else
        nCurrTimeStr = "(not_created)"
        nTimestepStr = "(not_created)"
      endif
      write (logMsg, "(A,(A,A,A),(A,A))") trim(cname)//": ", &
        "Nest(",trim(nStr),") ", &
        "Current Time = ",trim(nCurrTimeStr)
      call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)
      write (logMsg, "(A,(A,A,A),(A,A))") trim(cname)//": ", &
        "Nest(",trim(nStr),") ", &
        "Time Step    = ",trim(nTimestepStr)
      call ESMF_LogWrite(trim(logMsg),ESMF_LOGMSG_INFO)

    end subroutine

  end subroutine

  !-----------------------------------------------------------------------------

  subroutine ModelFinalize(gcomp,rc)
    type(ESMF_GridComp)  :: gcomp
    integer, intent(out) :: rc

    ! Local Variables
    character(32)              :: cname
    character(*), parameter    :: rname="ModelFinalize"
    integer                    :: verbosity, diagnostic
    character(len=64)          :: value
    type(type_InternalState)   :: is
    integer                    :: stat
    type(ESMF_Clock)           :: modelClock
    type(ESMF_Time)            :: currTime
    character(len=32)          :: currTimeStr
    character(len=9)           :: nStr

    rc = ESMF_SUCCESS

    ! Query component for name, verbosity, and diagnostic values
!    call NUOPC_CompGet(gcomp, name=name, verbosity=verbosity, &
!      diagnostic=diagnostic, rc=rc)
    call ESMF_GridCompGet(gcomp, name=cname, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Diagnostic", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    diagnostic = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    call ESMF_AttributeGet(gcomp, name="Verbosity", value=value, &
      defaultValue="0", convention="NUOPC", purpose="Instance", rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    verbosity = ESMF_UtilString2Int(value, &
      specialStringList=(/"min","max","bit16","maxplus"/), &
      specialValueList=(/0,65535,65536,131071/), rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query Component for its internal State
    nullify(is%wrap)
    call ESMF_UserCompGetInternalState(gcomp, label_InternalState, is, rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    ! query the Component for its clock
    call NUOPC_ModelGet(gcomp, modelClock=modelClock, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    call ESMF_ClockGet(modelClock, currTime=currTime, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    call ESMF_TimeGet(currTime, timeString=currTimeStr, rc=rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    write (nStr,"(I0)") is%wrap%did

    ! Write export file
    if (is%wrap%writeRestart) then
      call NUOPC_Write(is%wrap%NStateExp(1), &
        fileNamePrefix=trim(is%wrap%dirOutput)//"/restart_"//trim(cname)// &
          "_exp_D"//trim(nStr)//"_"//trim(currTimeStr)//"_", &
          overwrite=.true., status=ESMF_FILESTATUS_REPLACE, timeslice=1, rc=rc)
      if (ESMF_STDERRORCHECK(rc)) return  ! bail out
    endif

    call wrfhydro_nuopc_fin(is%wrap%did,rc)
    if (ESMF_STDERRORCHECK(rc)) return  ! bail out

    deallocate(is%wrap, stat=stat)
    if (ESMF_LogFoundDeallocError(statusToCheck=stat, &
      msg='WRFHYDRO: Deallocation of internal state memory failed.', &
      file=FILENAME,rcToReturn=rc)) return ! bail out

  end subroutine

end module
